package com.itlong.cloud.smartcard.service.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardOldDeviceInfoDTO;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardOldGetDevicesPageDTO;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardOldUpdateDeviceInfoDTO;
import com.itlong.cloud.POJO.PO.DeviceElevatorFloorConfigPO;
import com.itlong.cloud.POJO.PO.DeviceElevatorInfoPO;
import com.itlong.cloud.POJO.PO.DeviceEntranceInfoPO;
import com.itlong.cloud.POJO.VO.smartcard.SmartCardOldDeviceInfoVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.constants.RabbitMQConstant;
import com.itlong.cloud.constants.RedisConstant;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.enumerate.PropertyEquipTypeEnum;
import com.itlong.cloud.property.dao.IDeviceElevatorFloorConfigDao;
import com.itlong.cloud.property.dao.IDeviceEntranceInfoDao;
import com.itlong.cloud.property.dao.IPropertyElevatorDao;
import com.itlong.cloud.rabbitmq.config.MessageSender;
import com.itlong.cloud.service.RedisService;
import com.itlong.cloud.smartcard.dao.ISmartCardOldDeviceDao;
import com.itlong.cloud.smartcard.service.ISmartCardOldDeviceInfoService;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * <desc>
 *      旧一卡通_更新电梯楼层对应表数据接口实现类。
 * <desc/>
 *
 * @createDate 2017/11/22.
 */
@Service
public class SmartCardOldDeviceInfoServiceImpl implements ISmartCardOldDeviceInfoService {
    private static final Object lockStatic = new Object();
    private static final Logger LOG = LoggerFactory.getLogger(SmartCardOldDeviceInfoServiceImpl.class);

    //待发送消息列表Key（防止频繁发送消息）
    private static final String delaySendMessageKey = "OldSmartCardNotiyRefreshAuth";
    private final static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    private static boolean sendMessageThreadRunning = false;

    @Autowired
    RedisService<List<String>> redisService;
    @Autowired
    MessageSender messageSender;

    //电梯楼层映射操作数据接口
    @Autowired
    IDeviceEntranceInfoDao iDeviceEntranceInfoDao;
    @Autowired
    IPropertyElevatorDao iPropertyElevatorDao;
    @Autowired
    IDeviceElevatorFloorConfigDao iDeviceElevatorFloorConfigDao;

    ////旧一卡通设备操作数据库接口
    @Autowired
    ISmartCardOldDeviceDao iSmartCardOldDeviceDao;


    @PostConstruct
    private void initExec(){
        //启动时检查redis中是否有待发消息
        this.sendDelayMessage(null);
    }

    /**
     * <desc>
     *      发送延迟通知消息
     * <desc/>
     *
     * @param projectId
     * @return
     * @author Chunjian.G
     * @createDate 2018-03-02
     */
    private void sendDelayMessage(String projectId) {
        //1.保存到redis中
        if (StringUtils.isNotBlank(projectId)){
            List<String> delayMessageSendList = redisService.decodeObject(delaySendMessageKey,
                    new TypeReference<List<String>>() {
            });
            if (null == delayMessageSendList){
                delayMessageSendList = new ArrayList<>();
            }
            if (!delayMessageSendList.contains(projectId)){
                delayMessageSendList.add(projectId);
                redisService.set(delaySendMessageKey, RedisConstant.REDIS_APP_USER_DEVICE_CACHE_TIME, delayMessageSendList);
            }
        }

        synchronized (lockStatic){
            if (!sendMessageThreadRunning){
                //2.未执行则启动线程任务
                singleThreadExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            synchronized (lockStatic){
                                sendMessageThreadRunning = true;
                            }
                            List<String> delayMessageSendList;
                            try {
                                delayMessageSendList = redisService.decodeObject(delaySendMessageKey, new TypeReference<List<String>>() {
                                });
                                if (null == delayMessageSendList || delayMessageSendList.isEmpty()){
                                    return;
                                }
                                Thread.sleep(60000);
                            }finally {
                                synchronized (lockStatic){
                                    sendMessageThreadRunning = false;
                                }
                            }


                            delayMessageSendList = redisService.decodeObject(delaySendMessageKey, new TypeReference<List<String>>() {
                            });
                            if (null == delayMessageSendList || delayMessageSendList.isEmpty()){
                                return;
                            }
                            Iterator<String> entryIterator = delayMessageSendList.iterator();
                            while (entryIterator.hasNext()){
                                String projectId = entryIterator.next();
                                Map<String, Object> param = new HashMap<>();
                                param.put("projectId", projectId);
                                messageSender.send(RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_INFO_DEVICE_UPDATE_QUEUE,
                                        JSON.toJSONString(param), RabbitMQConstant.RABBITMQ_EQUIP_EXCHANGE,
                                        RabbitMQConstant.RABBITMQ_EQUIP_APP_USER_INFO_DEVICE_UPDATE_KEY);

                                //LOG.info(String.format("通知刷新整个项目app权限：projectId-%s", projectId));
                            }
                            //重新取最新缓存数据
                            List<String> latestMessageSendList = redisService.decodeObject(delaySendMessageKey, new TypeReference<List<String>>() {
                            });
                            if (null != latestMessageSendList){
                                latestMessageSendList.removeAll(delayMessageSendList);
                            }
                            //重新存入redis
                            redisService.set(delaySendMessageKey, RedisConstant.REDIS_APP_USER_DEVICE_CACHE_TIME, latestMessageSendList);

                        }catch (Exception e){
                            LOG.info("旧一卡通设备变更通知整个项目刷新app权限异常：" + e);
                        }
                    }
                });
            }
        }
    }


    /**
     * <desc>
     *      旧_更新电梯楼层对应表事务
     * <desc/>
     *
     * @param saveDTO
     * @return
     * @author Chunjian.G
     * @createDate 2018-03-02
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer updateFloorConfigTrans(SmartCardOldDeviceInfoDTO saveDTO) throws Exception{
        String[] logicalFloorArr = null,terminalFloorArr = null,naturalFloorArr = null;
        //楼层名称//楼层名称
        if (StringUtils.isNotEmpty(saveDTO.getLogicalFloor())) {
            logicalFloorArr = StringHandlerUtil.splitString(saveDTO.getLogicalFloor());
        }
        //端子
        if (StringUtils.isNotEmpty(saveDTO.getTerminalFloor())) {
            terminalFloorArr =  StringHandlerUtil.splitString(saveDTO.getTerminalFloor());
        }
        //楼层标识
        if (StringUtils.isNotEmpty(saveDTO.getNaturalFloor())) {
            naturalFloorArr = StringHandlerUtil.splitString(saveDTO.getNaturalFloor());
        }
        //查询设备对应的原始楼层对应信息列表ID
        List<DeviceElevatorFloorConfigPO>  floorConfigList = iDeviceElevatorFloorConfigDao.getFloorConfigIdList(saveDTO.getDeviceUnique());
        List<DeviceElevatorFloorConfigPO> addFloorConfigList = new ArrayList<>();  //需要添加楼层对应表信息
        List<DeviceElevatorFloorConfigPO> updateFloorConfigList = new ArrayList<>(); //更新楼层对应表信息
        if ((logicalFloorArr != null)&&(logicalFloorArr.length != 0)) {
            if(floorConfigList!=null&&floorConfigList.size()>0){
                for (int i = 1; i <= 112; i++){
                    boolean exist = false;//后台是否已存在对应楼层记录
                    for (int j = 0; j < floorConfigList.size(); j++){
                        Integer nfloor = StringHandlerUtil.strToIntDef(floorConfigList.get(j).getNaturalFloor(), 0);
                        if (nfloor == i){
                            floorConfigList.get(j).setLogicalFloor(logicalFloorArr[i - 1]);
                            if (terminalFloorArr != null){
                                floorConfigList.get(j).setTerminalFloor(terminalFloorArr[i - 1]);
                            }
                            floorConfigList.get(j).setUpdateTime(new Date());
                            updateFloorConfigList.add(floorConfigList.get(j));
                            exist = true;
                            break;
                        }
                    }
                    if (!exist){//不存在则添加
                        DeviceElevatorFloorConfigPO floorConfigAdd = new DeviceElevatorFloorConfigPO();
                        floorConfigAdd.setDeviceUnique(saveDTO.getDeviceUnique());
                        floorConfigAdd.setLogicalFloor(logicalFloorArr[i - 1]);
                        floorConfigAdd.setCreateTime(new Date());
                        floorConfigAdd.setUpdateTime(new Date());
                        floorConfigAdd.setStatus(1);
                        if(naturalFloorArr != null){
                            floorConfigAdd.setNaturalFloor(naturalFloorArr[i - 1]);
                        }
                        if(terminalFloorArr !=null){
                            floorConfigAdd.setTerminalFloor(terminalFloorArr[i - 1]);
                        }
                        addFloorConfigList.add(floorConfigAdd);
                    }
                }
            }else {
                for(int i=0;i<logicalFloorArr.length;i++){
                    DeviceElevatorFloorConfigPO floorConfigAdd = new DeviceElevatorFloorConfigPO();
                    floorConfigAdd.setDeviceUnique(saveDTO.getDeviceUnique());
                    floorConfigAdd.setLogicalFloor(logicalFloorArr[i]);
                    floorConfigAdd.setCreateTime(new Date());
                    floorConfigAdd.setUpdateTime(new Date());
                    floorConfigAdd.setStatus(1);

                    if(naturalFloorArr != null){
                        floorConfigAdd.setNaturalFloor(naturalFloorArr[i]);
                    }
                    if(terminalFloorArr !=null){
                        floorConfigAdd.setTerminalFloor(terminalFloorArr[i]);
                    }
                    addFloorConfigList.add(floorConfigAdd);
                }
            }
        }
        Integer count=0;
        if (addFloorConfigList != null&&addFloorConfigList.size() != 0) {
            count = iDeviceElevatorFloorConfigDao.saveBatch(addFloorConfigList);
        }
        if(updateFloorConfigList!=null && updateFloorConfigList.size()!=0){
            count = iDeviceElevatorFloorConfigDao.updateBatch(updateFloorConfigList);
        }
        return count;
    }

    /**
     * <desc>
     *      更新电梯楼层对应表。
     * <desc/>
     *
     * @param  saveDTO 请求参数
     * @return
     * @author shengen.T
     * @createDate 2017/11/22
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Integer updateFloorConfig(SmartCardOldDeviceInfoDTO saveDTO) throws Exception{
        Integer res = this.updateFloorConfigTrans(saveDTO);
        if (res > 0){
            //楼层对应表更新后，需要通知刷新app权限
            this.sendDelayMessage(StringHandlerUtil.getProjectIdByDeviceUnique(saveDTO.getDeviceUnique()));
        }
        return res;
    }


    /**
     * <desc>
     *      旧_一卡通获取设备列表。
     * <desc/>
     *
     * @param  pageDTO 请求参数
     * @return
     * @author shengen.T
     * @createDate 2017-12-05
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.NOT_SUPPORTED)
    public Page<SmartCardOldDeviceInfoVO> getDevicePage(SmartCardOldGetDevicesPageDTO pageDTO) throws Exception{
        //将DTO转换为Map params
        Map<String, Object> params = new HashMap<>();
        //分页类默认pageSize为20
        Page<SmartCardOldDeviceInfoVO> page = new Page<>();
        page.getPage().setPageSize(pageDTO.getPageSize());
        page.getPage().setCurrentPage(pageDTO.getPageNo());
        params.put("currentPage",page.getPage().getStartSlip());
        params.put("pageSize",page.getPage().getPageSize());
        params.put("projectId",pageDTO.getProjectId());
        Integer deviceType = StringHandlerUtil.strToIntDef(pageDTO.getDeviceType(),-1);
        //填充返回数据集
        if(deviceType== PropertyEquipTypeEnum.ELEVATOR.getType()){
            // page.setRows(iSmartCardOldDeviceDao.getElevatorDeviceList(params),iSmartCardOldDeviceDao.getElevatorCount(params));旧一卡通不需要查询设备信息，只需要获取记录数
            page.setRows(null,2048);
        }else if(deviceType== PropertyEquipTypeEnum.ENTRANCE.getType()){
            //page.setRows(iSmartCardOldDeviceDao.getEntranceDeviceList(params),iSmartCardOldDeviceDao.getEntranceCount(params));
            page.setRows(null,2048);
        }else {
            page.setRows(null);
        }
        return page;
    }


    /**
     * <desc>
     *      旧_一卡通更新设备信息事务
     * <desc/>
     *
     * @param updateDTO
     * @return
     * @author Chunjian.G
     * @createDate 2018-03-02
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean updateDeviceInfoTrans(SmartCardOldUpdateDeviceInfoDTO updateDTO) throws Exception{
        Integer resCount=0;
        boolean resFlag=false;
        if(PropertyEquipTypeEnum.ELEVATOR.getType()==updateDTO.getDeviceType()){
            DeviceElevatorInfoPO elevatorInfoPO = new DeviceElevatorInfoPO();
            elevatorInfoPO.setDeviceUnique(updateDTO.getDeviceUnique());
            elevatorInfoPO.setDeviceName(updateDTO.getDeviceName());
            elevatorInfoPO.setProjectId(updateDTO.getProjectId());
            if(StringUtils.isNotEmpty(updateDTO.getCommonFloor())){
                elevatorInfoPO.setCommonFloor(updateDTO.getCommonFloor());
            }
            if(StringUtils.isNotEmpty(updateDTO.getDeviceMemo())){
                elevatorInfoPO.setDeviceMemo(updateDTO.getDeviceMemo());
            }
            elevatorInfoPO.setUpdateTime(new Date());
            //保存电梯设备信息
            resCount = iSmartCardOldDeviceDao.updateElevatorDevice(SqlUtil.durableData(elevatorInfoPO, PlatformConstants.TABLE_UPDATE));
        }else if(PropertyEquipTypeEnum.ENTRANCE.getType()==updateDTO.getDeviceType()){
            DeviceEntranceInfoPO entranceInfoPO = new DeviceEntranceInfoPO(
                    updateDTO.getDeviceUnique(),
                    updateDTO.getDeviceId(),
                    updateDTO.getDeviceName(),
                    updateDTO.getProjectId()
            );
            entranceInfoPO.setUpdateTime(new Date());
            if(StringUtils.isNotEmpty(updateDTO.getDeviceMemo())){
                entranceInfoPO.setDeviceMemo(updateDTO.getDeviceMemo());
            }
            resCount = iSmartCardOldDeviceDao.updateElevatorDevice(SqlUtil.durableData(entranceInfoPO, PlatformConstants.TABLE_UPDATE));
        }
        if(resCount>0){
            resFlag = true;
        }
        return resFlag;
    }

    /**
     * <desc>
     *      旧_一卡通更新设备信息。
     * <desc/>
     *
     * @param updateDTO 更新设备信息参数
     * @return
     * @author shengen.T
     * @createDate 2017-12-12
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public boolean updateDeviceInfo(SmartCardOldUpdateDeviceInfoDTO updateDTO) throws Exception{
        boolean resFlag = this.updateDeviceInfoTrans(updateDTO);
        if (resFlag){
            //设备信息更新后，需要通知刷新app权限
            this.sendDelayMessage(StringHandlerUtil.getProjectIdByDeviceUnique(updateDTO.getDeviceUnique()));
        }
        return resFlag;
    }

    /**
     * <desc>
     *      旧一卡通_添加设备。
     * <desc/>
     *
     * @param  deviceInfo 设备信息
     * @return
     * @author shengen.T
     * @createDate 2017-12-12
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean addDeviceInfo(SmartCardOldUpdateDeviceInfoDTO deviceInfo) throws Exception{
        Integer resCount=0;
        boolean resFlag=false;
        if(PropertyEquipTypeEnum.ELEVATOR.getType()==deviceInfo.getDeviceType()){
            DeviceElevatorInfoPO elevatorInfoPO = new DeviceElevatorInfoPO(
                    deviceInfo.getDeviceUnique(),
                    deviceInfo.getDeviceName(),
                    deviceInfo.getProjectId(),
                    null,  //起始楼层
                    null, //结束楼层数
                    deviceInfo.getDeviceId()
            );
            elevatorInfoPO.setDeviceMemo(deviceInfo.getDeviceMemo());
            elevatorInfoPO.setCreateTime(new Date());
            elevatorInfoPO.setUpdateTime(new Date());
            elevatorInfoPO.setCommonFloor(deviceInfo.getCommonFloor());
            //保存电梯设备信息
            resCount = iSmartCardOldDeviceDao.addElevatorDevice(SqlUtil.durableData(elevatorInfoPO, PlatformConstants.TABLE_SAVE));
            if (deviceInfo.getElevatorFloorConfigPOList() != null&&deviceInfo.getElevatorFloorConfigPOList().size() != 0) {
                iDeviceElevatorFloorConfigDao.saveBatch(deviceInfo.getElevatorFloorConfigPOList());
            }
        }else if(PropertyEquipTypeEnum.ENTRANCE.getType()==deviceInfo.getDeviceType()){
            DeviceEntranceInfoPO entranceInfoPO = new DeviceEntranceInfoPO(
                    deviceInfo.getDeviceUnique(),
                    deviceInfo.getDeviceId(),
                    deviceInfo.getDeviceName(),
                    deviceInfo.getProjectId()
            );
            entranceInfoPO.setDeviceMemo(deviceInfo.getDeviceMemo());
            entranceInfoPO.setCreateTime(new Date());
            resCount = iSmartCardOldDeviceDao.addEntranceDevice(SqlUtil.durableData(entranceInfoPO, PlatformConstants.TABLE_SAVE));
        }
        if(resCount>0){
            resFlag = true;
        }
        return resFlag;
    }



    /**
     * <desc>
     * 获取某项目中的设备唯一码列表
     * <desc/>
     *
     * @param projectId  项目编号
     * @param deviceType 设备类型：1-电梯，2-门禁
     * @return
     * @author Chunjian.G
     * @createDate 2017-12-15
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<String> getDeviceUniques(String projectId, Integer deviceType) throws Exception {
        List<String> devUniques = null;
        if (PropertyEquipTypeEnum.ELEVATOR.getType().equals(deviceType)){
            devUniques = iPropertyElevatorDao.getDeviceUniquesByProjectId(projectId);
        }else if (PropertyEquipTypeEnum.ENTRANCE.getType().equals(deviceType)){
            devUniques = iDeviceEntranceInfoDao.getDeviceUniquesByProjectId(projectId);
        }
        return devUniques;
    }

    /**
     * <desc>
     * 添加默认设备
     * <desc/>
     *
     * @param deviceUniques 设备唯一码列表
     * @param deviceType    设备类型：1-电梯，2-门禁
     * @param projectId 项目编号
     * @return
     * @author Chunjian.G
     * @createDate 2017-12-15
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer addDefaultDevices(List<String> deviceUniques, Integer deviceType, String projectId) throws Exception {
        Integer res = null;
        if (PropertyEquipTypeEnum.ELEVATOR.getType().equals(deviceType)){
            List<DeviceElevatorInfoPO> list = new ArrayList<>();
            for (String devUnique: deviceUniques){
                DeviceElevatorInfoPO elevatorInfoPO = new DeviceElevatorInfoPO();
                elevatorInfoPO.setDeviceUnique(devUnique);
                elevatorInfoPO.setDeviceId(StringHandlerUtil.getDeviceIdByDeviceUnique(devUnique));
                elevatorInfoPO.setDeviceName(elevatorInfoPO.getDeviceId() + PropertyEquipTypeEnum.ELEVATOR.getDescription());
                elevatorInfoPO.setProjectId(projectId);
                elevatorInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
                //elevatorInfoPO.setFloorNo(1);
                //elevatorInfoPO.setFloorNoMax(PlatformConstants.MAX_ELEVATOR_FLOORNUM);
                elevatorInfoPO.setOpenThreshold(PlatformConstants.EQUIP_BLUETOOTH_OPEN_THRESHOLD);
                elevatorInfoPO.setCreateTime(new Date());
                elevatorInfoPO.setUpdateTime(elevatorInfoPO.getCreateTime());
                list.add(elevatorInfoPO);
                //新添加的设备没有楼层对应表，需添加默认值
                addElevatorFloor(elevatorInfoPO);
            }
            res = iPropertyElevatorDao.saveBatch(list);

        }else if (PropertyEquipTypeEnum.ENTRANCE.getType().equals(deviceType)){
            List<DeviceEntranceInfoPO> list = new ArrayList<>();
            for (String devUnique: deviceUniques){
                DeviceEntranceInfoPO entranceInfoPO = new DeviceEntranceInfoPO();
                entranceInfoPO.setDeviceUnique(devUnique);
                entranceInfoPO.setDeviceId(StringHandlerUtil.getDeviceIdByDeviceUnique(devUnique));
                entranceInfoPO.setDeviceName(entranceInfoPO.getDeviceId() + PropertyEquipTypeEnum.ENTRANCE.getDescription());
                entranceInfoPO.setProjectId(projectId);
                entranceInfoPO.setOpenThreshold(PlatformConstants.EQUIP_BLUETOOTH_OPEN_THRESHOLD);
                entranceInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
                entranceInfoPO.setCreateTime(new Date());
                entranceInfoPO.setUpdateTime(entranceInfoPO.getCreateTime());
                list.add(entranceInfoPO);
            }
            res = iDeviceEntranceInfoDao.saveBatch(list);
        }
        return res;
    }

    /**
     * <desc>
     *      生成电梯楼层映射表,仅供测试使用
     * <desc/>
     * @param   deviceElevatorInfoPO  电梯实体对象
     * @author Biao.R
     * @createDate 2017/11/27
     */
    private void addElevatorFloor(DeviceElevatorInfoPO deviceElevatorInfoPO) {
//        Integer floorNo = deviceElevatorInfoPO.getFloorNo();
//        Integer floorNoMax = deviceElevatorInfoPO.getFloorNoMax();
        String deviceUnique = deviceElevatorInfoPO.getDeviceUnique();
        iDeviceElevatorFloorConfigDao.delByDeviceUnique(deviceUnique);
        List<DeviceElevatorFloorConfigPO> floorConfigPOList = new ArrayList<>();
        for (int i = 1; i <= PlatformConstants.MAX_ELEVATOR_FLOORNUM; i++) {
            DeviceElevatorFloorConfigPO floorConfigPO = new DeviceElevatorFloorConfigPO(String.format("%d%s", i, "层"), deviceUnique, i+"");
            floorConfigPO.setStatus(DataStatusEnum.NORMAL.getType());
            floorConfigPO.setCreateTime(new Date());
            floorConfigPOList.add(floorConfigPO);
        }
        if (!floorConfigPOList.isEmpty()) {
            iDeviceElevatorFloorConfigDao.saveBatch(floorConfigPOList);
        }
    }
}
